#include "globals.h"
#define TAM_VAIBO_INIT 4
using namespace std;

//Constructores------------------------------------------------------------------
Juego::Juego(): m_players(1)
{
	m_restart= true;
	m_end= false;

	//Keep track of the current frame
	m_frame = 0;
	//Whether or not to cap the frame rate
	m_cap = true;

	m_mode= 1 ;
	pair<int,int>resolution;
	resolution.first= 64;
	resolution.second= 48;

	m_map= new Mapa(m_mode, resolution);
	m_end= m_map->error();

}

Juego::Juego(const Juego& juego)
{
	cerr << "entra al const por copia de Juego" << endl;
}


//Destructor ------------------------------------------------------------------
Juego::~Juego()
{
	vector<Vibora*>::iterator iter, end;
	iter= m_players.begin();
	end= m_players.end();
	while( iter != end)
	{
		delete *iter;
		iter++;
	}
	delete m_map;
	SDL_Quit();
}


void Juego::start(unsigned short nplayers)  //puerta de entrada
{
	SDL_Event event;

	m_restart= true;
	while(m_restart)
	{
		m_input = cInput();

		m_players.clear();
		m_players.resize(nplayers);
		initVaibos();

		m_end= false;

		//Keep track of the current frame
		m_frame = 0;
		//Whether or not to cap the frame rate
		m_cap = true;

		m_mode= 1 ;
		pair<int,int>resolution;
		resolution.first= 64;
		resolution.second= 48;

		m_map= new Mapa(m_mode, resolution);
		m_end= m_map->error(); //if an error happend while creating the map the game doesn't start

		go(event);

		m_end= true;

		while( m_end) //waits until a valid key comes
		{
			SDL_WaitEvent(&event);
			if( event.type == SDL_QUIT || event.key.keysym.sym == SDLK_RETURN)
			{
				m_restart= false;
				m_end= false;
			}
			if( event.key.keysym.sym == SDLK_y )
			{
				m_restart= true;
				m_end= false;
			}
		}

	}
}

//Ciclo principal--------------------------------------------------------------
void Juego::go( SDL_Event event ) //es
{
	SDL_Surface*  background= m_map->getBackground();
	SDL_Surface* screen=  m_map->getScreen();

	vaibosGrow(TAM_VAIBO_INIT, background, screen); //hago crecer un poco a las viboras para que se vean más lindas, y para probar que la funcion grow anda bien tempranamente.
	m_map->giveFood();

	m_end= false; //condicion de juego terminado

	
	const int TICKS_PER_SECOND = 20;
	const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
	const int MAX_FRAMESKIP = 10;

	Uint32 next_game_tick = SDL_GetTicks();
	int loops;

        while(!m_end)//ciclo principal
	{
		loops = 0;
		//
		while( SDL_GetTicks() > next_game_tick && loops < MAX_FRAMESKIP)
		{
			for( int i= m_players.size() - 1; i >= 0; i-- )
			{
				m_players[i]->move();
			}

			gameState(); //checks the state, if a vaibo eats food, or if it crash into another

			next_game_tick += SKIP_TICKS;
			loops++;
		}

		m_map->print(); //Vuelvo a imprimir el mapa (antes de los jugadores)
		prints_vaibos(background,screen); //prints the characters (for now just vaibos)		
		input(event);  //update the players input

	}

	m_end= false;//loop para mostrar algo de salida, o no sé, para algo
}


//Otros métodos-------------------------------------------------------------------

void Juego::prints_vaibos(SDL_Surface* background, SDL_Surface* screen)
{
		for( int i= m_players.size() - 1; i >= 0; i-- )
		{
			m_players[i]->print(background, screen);
		}
		if( SDL_Flip( screen ) == -1 )m_end= true;
}

void Juego::gameState()
{
	//Chequeo estados
	for( unsigned int i= 0; i < m_players.size(); i++ )
	{
		if(m_map->isBlock(m_players[i]->getPos()) ) m_end= true; //esta vibora está en una pared o fuera del borde
		if( hitVaibo( m_players[i], i ) ) m_end= true; //esta vibora chocó a otra
		vaiboEats(m_players[i]);
	}
}

void Juego::input(SDL_Event event	 )
{
	m_input.Update();

	for( int i= m_players.size() - 1; i >= 0; i-- )
	{
		//Veo que teclas estan apretadas para cada jugador
		checkKeyboard( m_players[i] );
	}
}


void Juego::checkKeyboard( Vibora* vaibo )
{
	//Actualizo cada jugador
	eKey up = (vaibo->m_keys)["UP"];
	eKey down = (vaibo->m_keys)["DOWN"];
	eKey left = (vaibo->m_keys)["LEFT"];
	eKey right = (vaibo->m_keys)["RIGHT"];

	Direcciones dirUp = UP;
	Direcciones dirDown = DOWN;
	Direcciones dirLeft = LEFT;
	Direcciones dirRight = RIGHT;

	if( m_input.IsKeyDown(up) ) vaibo->updateKeyBuffer( dirUp );
	if(  m_input.IsKeyDown(down) ) vaibo->updateKeyBuffer( dirDown );
	if(  m_input.IsKeyDown(left) ) vaibo->updateKeyBuffer( dirLeft );
	if(  m_input.IsKeyDown(right) ) vaibo->updateKeyBuffer( dirRight );
}


/*A esta funcion le paso un puntero a vibora, el indice que de su posicion en m_players y chequeo si su cabeza choco contra alguna de todas las otras viboras.
Para hacer esto toma la posicion de la cabeza, y voy recorriendo una a una las otras viboras, posicion por posicion. La complejidad temporal es: horrible (#viboras*#viboras)*/
bool Juego::hitVaibo(Vibora* vaibo, unsigned int numVaibo)
{
	const int pos= vaibo->getPos(); //tomo la posicion de la cabeza de la vibora
	bool hit= false;
	bool estaVibora =false;
	
	for( unsigned int i= 0; i < m_players.size() ; i++)
	{
		estaVibora =  i == numVaibo;
		hit= m_players[ i ]->hit( pos, estaVibora );
		if( hit ) break; //si chocó con alguna vibora ya no sigo buscando
	}


	return hit;
}

//this function has a precondition, which is: if two (or more) vaibos were to eat the same food at the same time,
// they would have crashed and the game should ends, so this function is always "fair".
//The function looks where the food is on the map and checks if this vaibo is on the same tile.
void Juego::vaiboEats( Vibora* vaibo)
{
	string type= "free";
	const int food = m_map->food();

	if( vaibo->hit( food ) )
	{
		vaibo->grow(1);
		m_map->changeType(food, type);
		m_map->giveFood();
	}
}

//Metodos del sistema/inicializacion

void Juego::initVaibos()
{
	string vaibo= "";
	string playerUp= "";
	string playerRight= "";
	string playerDown= "";
	string playerLeft= "";

	for( unsigned int i= 0; i <= m_players.size() - 1; i++)
	{
		//convierto el int a string, pasando por un streamstring
		stringstream ssi;
		string si;
		ssi << i;
		ssi >> si;

		//inicio los valores a los que voy a concatenar
		vaibo= "vaibo";
		vaibo.append(si);

		//Inicializo las teclas a las que va a escuchar cada vibora. POR AHORA TODAS ESTAN IGUALES
		eKey keys[4] = {KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT};

		Direcciones dir = RIGHT;

		//Inicializo las viboras
		//
		m_players[ i ]= new Vibora( 80+64*20*i, dir, vaibo, keys );// CAMBIAR ESTO! la posicion de inicio de cada vivora tiene que ser algo coherente
		m_players[ i ]->showPos();

	}
}

//hace crecer a la vibora
void Juego::vaibosGrow(int cantidad, SDL_Surface*  background, SDL_Surface*  screen)
{
	for(int i=m_players.size() -1; i>=0; i--)
	{
		m_players[i]->showPos();
		m_players[i]->grow(cantidad);
		m_players[i]->print(background, screen);
	}
	if( SDL_Flip( screen ) == -1 )m_end= true;
}
